﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Text;
using System.Net;
using System.Globalization;
using System.Xml;

namespace Nuane.Posterous
{
	/// <summary>
	/// The content of an existing posterous post.
	/// </summary>
	public class PosterousPost
	{
		//<post>
		//  <url>http://post.ly/abc123</url>  
		//  <link>http://sachin.posterous.com/brunch-in-san-francisco  
		//  <title>Brunch in San Francisco</title>  
		//  <id>55</id>  
		//  <body><![CDATA[What a great brunch!]]></body>  
		//  <date>Sun, 03 May 2009 19:58:58 -0700</date>  
		//  <views>0</views>  
		//  <private>false</private>  
		//  <author>sachin agarwal</author>  
		//  <authorpic>http://debug2.posterous.com/user_profile_pics/16071/Picture_1_thumb.png</authorpic>  
		//  <commentsenabled>true</commentsenabled>  
		//  <media>
		//    <type>image/audio/video</type>  
		//    ...
		//  </media>  
		//  <commentscount>0</commentscount>  
		//  <comment>  
		//    ...
		//  </comment>  
		//</post>

		private readonly PosterousSession _session;
		private string _title;
		private string _body;
		private string _originalTitle;
		private string _originalBody;

		/// <summary>
		/// Gets the short Post.ly URI of this post.
		/// </summary>
		/// <value>Short URI.</value>
		public Uri ShortUri { get; private set; }

		/// <summary>
		/// Gets the Post.ly shortcode of this post (the ABCD part in http://post.ly/ABCD). Can be used in <see cref="PosterousSession.GetPost(string)"/>
		/// </summary>
		public string ShortCode
		{
			get { return ShortUri.Segments[1]; }
		}

		/// <summary>
		/// Gets the full URI of this post.
		/// </summary>
		/// <value>Full URI.</value>
		public Uri Uri { get; private set; }

		/// <summary>
		/// Gets the title of this post.
		/// </summary>
		/// <value>Post title.</value>
		public string Title
		{
			get { return _title; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_title = value;
			}
		}

		/// <summary>
		/// Gets the ID of this post.
		/// </summary>
		/// <value>Post ID.</value>
		public int Id { get; private set; }

		/// <summary>
		/// Gets the body of this post.
		/// </summary>
		/// <value>Post body.</value>
		public string Body
		{
			get { return _body; }
			set
			{
				if (value == null)
					throw new ArgumentNullException("value");

				_body = value;
			}
		}

		/// <summary>
		/// Gets the UTC datetime of this post.
		/// </summary>
		/// <value>Post UTC datetime.</value>
		public DateTime Date { get; private set; }

		/// <summary>
		/// Gets the numer of views of this post.
		/// </summary>
		/// <value>Number of views.</value>
		public int Views { get; private set; }

		/// <summary>
		/// Gets a value indicating whether the post is private.
		/// </summary>
		/// <value>True if private; false if not private.</value>
		public bool IsPrivate { get; private set; }

		/// <summary>
		/// Gets the post author.
		/// </summary>
		/// <value>Post author.</value>
		public string Author { get; private set; }

		/// <summary>
		/// Gets the post author picture URI, if available;
		/// </summary>
		/// <value>Post author picture URI; or null (Nothing in VB.NET) if not available.</value>
		public Uri AuthorPictureUri { get; private set; }

		/// <summary>
		/// Gets a value indicating whether comments are enabled for this post.
		/// </summary>
		/// <value>True if enabled; false if disabled.</value>
		public bool CommentsEnabled { get; private set; }

		/// <summary>
		/// Gets a collection of the post's comments.
		/// </summary>
		/// <value>Comments collection.</value>
		public PosterousCommentCollection Comments { get; private set; }

		/// <summary>
		/// Gets a collection of the post's images.
		/// </summary>
		/// <value>Images collection.</value>
		public PosterousImageCollection Images { get; private set; }

		/// <summary>
		/// Gets a collection of the post's audios.
		/// </summary>
		/// <value>Audios collection.</value>
		public PosterousAudioCollection Audios { get; private set; }

		/// <summary>
		/// Gets a collection of the post's videos.
		/// </summary>
		/// <value>Videos collection.</value>
		public PosterousVideoCollection Videos { get; private set; }

		internal PosterousPost(PosterousSession session, XmlNode post, bool postlyResult)
		{
			_session = session;

			if (post.Name != "post")
				throw new PosterousException("Invalid response.", PosterousExceptionStatus.ServerProtocolViolation);

			ShortUri = Helper.ToUri(Helper.GetChildElementValue(post, "url"));
			Uri = Helper.ToUri(Helper.GetChildElementValue(post, "link"));
			_originalTitle = Title = Helper.GetChildElementValue(post, "title");
			Id = Helper.ToInt32(Helper.GetChildElementValue(post, "id"));

			_originalBody = Body = Helper.RemoveUnnecessaryEntities(Helper.GetChildElementValue(post, "body"));
			Date = Helper.ToDateTime(Helper.GetChildElementValue(post, "date"));
			Views = Helper.ToInt32(Helper.GetChildElementValue(post, "views"));
			if (postlyResult)
				IsPrivate = false;
			else
				IsPrivate = Helper.ToBoolean(Helper.GetChildElementValue(post, "private"));
			Author = Helper.GetChildElementValue(post, "author");
			AuthorPictureUri = Helper.ToUri(Helper.GetChildElementValue(post, "authorpic"));
			CommentsEnabled = Helper.ToBoolean(Helper.GetChildElementValue(post, "commentsenabled"));

			Comments = new PosterousCommentCollection();
			Images = new PosterousImageCollection();
			Audios = new PosterousAudioCollection();
			Videos = new PosterousVideoCollection();
			XmlNode child = post.FirstChild;
			while (child != null)
			{
				switch (child.Name)
				{
					case "comment":
						Comments.Add(new PosterousComment(child));
						break;
					case "media":
						string type = Helper.GetChildElementValue(child, "type");
						switch (type)
						{
							case "image":
								Images.Add(new PosterousImage(child));
								break;
							case "audio":
								Audios.Add(new PosterousAudio(child));
								break;
							case "video":
								Videos.Add(new PosterousVideo(child));
								break;
						}
						break;
				}
				child = child.NextSibling;
			}
		}

		/// <summary>
		/// Converts this post to a post info.
		/// </summary>
		/// <returns>Post info.</returns>
		public PosterousPostInfo ToPostInfo()
		{
			return new PosterousPostInfo(_session, this);
		}

		/// <summary>
		/// Updates the post's body and title.
		/// </summary>
		public void Update()
		{
			string title = null;
			string body = null;

			if (_originalTitle != _title)
				title = _title;

			if (_originalBody != _body)
				body = _body;

			_session.UpdatePost(Id, title, body);
		}

		/// <summary>
		/// Adds new media to this post.
		/// </summary>
		/// <param name="media">One or more media files.</param>
		public void AddMedia(params PosterousFile[] media)
		{
			_session.AddMedia(Id, media);
		}

		/// <summary>
		/// Adds a new comment to this post.
		/// </summary>
		/// <param name="comment">Comment.</param>
		public void AddComment(PosterousNewComment comment)
		{
			_session.AddComment(Id, comment);
		}

	}
}
